package com.example.demo.service.impl;

import com.example.demo.dto.Admin.*; // 统一导入 Admin DTOs
import com.example.demo.entity.Admin;
import com.example.demo.entity.Bookkeeping;
import com.example.demo.entity.User;
import com.example.demo.repository.AdminRepository;
import com.example.demo.repository.BookkeepingRepository; // 新增导入
import com.example.demo.repository.UserRepository;
import com.example.demo.service.AdminService;
import com.example.demo.service.BookkeepingService;
import jakarta.persistence.EntityNotFoundException; // 确保导入
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Optional;

@Service
public class AdminServiceImpl implements AdminService {

    private static final Logger log = LoggerFactory.getLogger(AdminServiceImpl.class);

    private final AdminRepository adminRepository;
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    private final BookkeepingService bookkeepingService;
    private final BookkeepingRepository bookkeepingRepository; // 新增注入

    @Autowired
    public AdminServiceImpl(AdminRepository adminRepository,
                            UserRepository userRepository,
                            @Qualifier("bCryptPasswordEncoder") PasswordEncoder passwordEncoder,
                            BookkeepingService bookkeepingService,
                            BookkeepingRepository bookkeepingRepository) { // 添加到构造函数
        this.adminRepository = adminRepository;
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
        this.bookkeepingService = bookkeepingService;
        this.bookkeepingRepository = bookkeepingRepository; // 初始化
    }

    // ... (已有的方法保持不变) ...
    @Override
    public Optional<Admin> getAdminByAccount(String account) {
        log.debug("根据账号查找管理员: {}", account);
        return adminRepository.findByAccount(account);
    }

    @Override
    @Transactional
    public Admin createAdmin(AdminCreationRequestDto requestDto) {
        log.info("尝试创建新管理员，账号: {}", requestDto.getAccount());

        if (adminRepository.findByAccount(requestDto.getAccount()).isPresent()) {
            String errorMessage = "管理员账号 '" + requestDto.getAccount() + "' 已存在。";
            log.warn("创建管理员失败：{}", errorMessage);
            throw new IllegalArgumentException(errorMessage);
        }

        Admin newAdmin = new Admin();
        newAdmin.setAccount(requestDto.getAccount());

        if (requestDto.getUsername() == null || requestDto.getUsername().trim().isEmpty()) {
            newAdmin.setUsername(requestDto.getAccount());
            log.debug("新管理员 {} 未提供用户名，使用账号作为默认用户名。", requestDto.getAccount());
        } else {
            newAdmin.setUsername(requestDto.getUsername());
        }

        newAdmin.setPassword(passwordEncoder.encode(requestDto.getPassword()));
        log.info("为管理员 {} 设置了加密后的密码。", requestDto.getAccount());

        Admin savedAdmin = adminRepository.save(newAdmin);
        log.info("新管理员 {} (ID: {}) 创建并保存成功。", savedAdmin.getAccount(), savedAdmin.getId());
        return savedAdmin;
    }

    @Override
    public List<Admin> getAllAdmins() {
        log.info("正在获取所有管理员列表...");
        List<Admin> admins = adminRepository.findAll();
        log.info("成功获取 {} 位管理员。", admins.size());
        return admins;
    }

    @Override
    @Transactional
    public Admin updateOwnAdminProfile(String currentAdminAccount, AdminSelfUpdateDto updateDto) {
        log.info("管理员 {} 请求更新自己的个人信息。", currentAdminAccount);

        Admin adminToUpdate = adminRepository.findByAccount(currentAdminAccount)
                .orElseThrow(() -> {
                    log.error("更新个人信息失败：找不到账号为 {} 的管理员（当前认证用户）。", currentAdminAccount);
                    return new UsernameNotFoundException("认证用户 '" + currentAdminAccount + "' 在数据库中未找到。");
                });

        boolean changed = false;
        String originalAccountForLog = adminToUpdate.getAccount();

        if (StringUtils.hasText(updateDto.getNewAccount()) && !updateDto.getNewAccount().equals(adminToUpdate.getAccount())) {
            String newAccount = updateDto.getNewAccount();
            log.info("管理员 {} 尝试将账号更新为: {}", originalAccountForLog, newAccount);
            Optional<Admin> existingAdminWithNewAccount = adminRepository.findByAccount(newAccount);
            if (existingAdminWithNewAccount.isPresent()) {
                String errorMessage = "更新失败：新账号 '" + newAccount + "' 已被其他管理员使用。";
                log.warn(errorMessage);
                throw new IllegalArgumentException(errorMessage);
            }
            adminToUpdate.setAccount(newAccount);
            log.info("管理员原账号 {} 已成功更新为 {}。", originalAccountForLog, adminToUpdate.getAccount());
            changed = true;
        }

        if (updateDto.getUsername() != null) {
            String newUsername = updateDto.getUsername().trim();
            if (!newUsername.equals(adminToUpdate.getUsername())) {
                if (StringUtils.hasText(newUsername)) {
                    adminToUpdate.setUsername(newUsername);
                } else {
                    adminToUpdate.setUsername(adminToUpdate.getAccount());
                    log.debug("管理员 {} 的用户名被设置为空，将使用其账号作为用户名。", adminToUpdate.getAccount());
                }
                log.info("管理员 {} 的用户名已更新为: {}", adminToUpdate.getAccount(), adminToUpdate.getUsername());
                changed = true;
            }
        }

        if (StringUtils.hasText(updateDto.getNewPassword())) {
            String newPassword = updateDto.getNewPassword();
            adminToUpdate.setPassword(passwordEncoder.encode(newPassword));
            log.info("管理员 {} 的密码已更新并加密。", adminToUpdate.getAccount());
            changed = true;
        }

        if (changed) {
            Admin savedAdmin = adminRepository.save(adminToUpdate);
            log.info("管理员 {} 的个人信息已成功更新。", savedAdmin.getAccount());
            return savedAdmin;
        } else {
            log.info("管理员 {} 的个人信息没有提供任何有效的更改，未执行数据库更新。", adminToUpdate.getAccount());
            return adminToUpdate;
        }
    }

    @Override
    @Transactional
    public void deleteOwnAdminAccount(String currentAdminAccount) {
        log.info("管理员 {} 请求删除自己的账户。", currentAdminAccount);

        Admin adminToDelete = adminRepository.findByAccount(currentAdminAccount)
                .orElseThrow(() -> {
                    log.error("删除账户失败：找不到账号为 {} 的管理员（当前认证用户）。", currentAdminAccount);
                    return new UsernameNotFoundException("认证用户 '" + currentAdminAccount + "' 在数据库中未找到，无法删除。");
                });

        adminRepository.delete(adminToDelete);
        log.info("管理员 {} (ID: {}) 的账户已成功删除。", adminToDelete.getAccount(), adminToDelete.getId());
    }

    @Override
    @Transactional
    public User adminAddUser(AdminUserCreationRequestDto creationRequestDto) {
        log.info("管理员尝试添加新用户，账号: {}", creationRequestDto.getAccount());

        if (userRepository.findByAccount(creationRequestDto.getAccount()).isPresent()) {
            String errorMessage = "用户账号 '" + creationRequestDto.getAccount() + "' 已存在。";
            log.warn("管理员添加用户失败：{}", errorMessage);
            throw new IllegalArgumentException(errorMessage);
        }
        if (adminRepository.findByAccount(creationRequestDto.getAccount()).isPresent()) {
            String errorMessage = "账号 '" + creationRequestDto.getAccount() + "' 已被管理员占用。";
            log.warn("管理员添加用户失败：{}", errorMessage);
            throw new IllegalArgumentException(errorMessage);
        }

        User newUser = new User();
        newUser.setAccount(creationRequestDto.getAccount());

        if (StringUtils.hasText(creationRequestDto.getUsername())) {
            newUser.setUsername(creationRequestDto.getUsername());
        } else {
            newUser.setUsername(creationRequestDto.getAccount());
            log.debug("新用户 {} 未提供用户名，使用账号作为默认用户名。", newUser.getAccount());
        }

        newUser.setPassword(passwordEncoder.encode(creationRequestDto.getPassword()));
        log.info("为新用户 {} 设置了加密后的密码。", newUser.getAccount());

        if (StringUtils.hasText(creationRequestDto.getAvatar())) {
            newUser.setAvatar(creationRequestDto.getAvatar());
        }

        User savedUser = userRepository.save(newUser);
        log.info("管理员成功添加新用户 {} (ID: {})。", savedUser.getAccount(), savedUser.getId());
        return savedUser;
    }

    @Override
    @Transactional
    public void adminDeleteUser(String userAccount) {
        log.info("管理员尝试删除用户，账号: {}", userAccount);
        User userToDelete = userRepository.findByAccount(userAccount)
                .orElseThrow(() -> {
                    log.warn("管理员删除用户失败：未找到账号为 {} 的用户。", userAccount);
                    return new UsernameNotFoundException("用户未找到，账号: " + userAccount);
                });
        userRepository.delete(userToDelete);
        log.info("管理员成功删除用户 {} (ID: {})。", userToDelete.getAccount(), userToDelete.getId());
    }

    @Override
    @Transactional
    public User adminUpdateUser(String originalUserAccount, AdminUserUpdateRequestDto updateDto) {
        log.info("管理员尝试更新用户 {} 的信息。", originalUserAccount);
        User userToUpdate = userRepository.findByAccount(originalUserAccount)
                .orElseThrow(() -> {
                    log.warn("管理员更新用户信息失败：未找到账号为 {} 的用户。", originalUserAccount);
                    return new UsernameNotFoundException("用户未找到，账号: " + originalUserAccount);
                });

        boolean changed = false;

        if (updateDto.getUsername() != null) {
            String newUsername = updateDto.getUsername();
            if (!newUsername.equals(userToUpdate.getUsername())) {
                userToUpdate.setUsername(newUsername);
                log.info("用户 {} 的用户名已更新为: '{}'", userToUpdate.getAccount(), newUsername);
                changed = true;
            }
        }

        if (StringUtils.hasText(updateDto.getNewAccount()) && !updateDto.getNewAccount().equals(userToUpdate.getAccount())) {
            String newAccountValue = updateDto.getNewAccount();
            log.info("用户 {} 尝试将账号更新为: {}", userToUpdate.getAccount(), newAccountValue);
            if (userRepository.findByAccount(newAccountValue).isPresent()) {
                String errorMessage = "更新失败：新账号 '" + newAccountValue + "' 已被其他用户使用。";
                log.warn(errorMessage);
                throw new IllegalArgumentException(errorMessage);
            }
            if (adminRepository.findByAccount(newAccountValue).isPresent()) {
                String errorMessage = "更新失败：新账号 '" + newAccountValue + "' 已被管理员占用。";
                log.warn(errorMessage);
                throw new IllegalArgumentException(errorMessage);
            }
            userToUpdate.setAccount(newAccountValue);
            log.info("用户原账号 {} 已成功更新为 {}。", originalUserAccount, userToUpdate.getAccount());
            changed = true;
        }

        if (StringUtils.hasText(updateDto.getNewPassword())) {
            userToUpdate.setPassword(passwordEncoder.encode(updateDto.getNewPassword()));
            log.info("用户 {} 的密码已由管理员更新并加密。", userToUpdate.getAccount());
            changed = true;
        }

        if (updateDto.getAvatar() != null) {
            if (!updateDto.getAvatar().equals(userToUpdate.getAvatar())) {
                userToUpdate.setAvatar(updateDto.getAvatar());
                log.info("用户 {} 的头像已更新。", userToUpdate.getAccount());
                changed = true;
            }
        }

        if (updateDto.getBookCount() != null && !updateDto.getBookCount().equals(userToUpdate.getBookCount())) {
            userToUpdate.setBookCount(updateDto.getBookCount());
            log.info("用户 {} 的记账数目已由管理员更新为: {}", userToUpdate.getAccount(), updateDto.getBookCount());
            changed = true;
        }

        if (changed) {
            User savedUser = userRepository.save(userToUpdate);
            log.info("管理员成功更新用户 {} 的信息。", savedUser.getAccount());
            return savedUser;
        } else {
            log.info("管理员未对用户 {} 的信息进行任何有效更改。", userToUpdate.getAccount());
            return userToUpdate;
        }
    }

    @Override
    public List<Bookkeeping> adminGetUserBookkeepingRecords(String userAccount) {
        log.info("管理员尝试查询用户 {} 的账本数据。", userAccount);
        User user = userRepository.findByAccount(userAccount)
                .orElseThrow(() -> {
                    log.warn("管理员查询用户账本失败：未找到账号为 {} 的用户。", userAccount);
                    return new UsernameNotFoundException("用户未找到，账号: " + userAccount);
                });

        List<Bookkeeping> records = bookkeepingService.getAllRecordsByUserId(user.getId());
        log.info("成功查询到用户 {} (ID: {}) 的 {} 条账本记录。", user.getAccount(), user.getId(), records.size());
        return records;
    }

    // --- 新增方法的实现 ---
    @Override
    @Transactional
    public Bookkeeping adminAddUserBookkeepingRecord(String userAccount, AdminBookkeepingCreationRequestDto recordDto) {
        log.info("管理员尝试为用户 {} 添加账本记录。", userAccount);
        User user = userRepository.findByAccount(userAccount)
                .orElseThrow(() -> {
                    log.warn("管理员添加用户账本失败：未找到账号为 {} 的用户。", userAccount);
                    return new EntityNotFoundException("用户未找到，账号: " + userAccount);
                });

        Bookkeeping newRecord = new Bookkeeping();
        newRecord.setType(recordDto.getType());
        newRecord.setBookDate(recordDto.getBookDate());
        newRecord.setCategory(recordDto.getCategory());
        newRecord.setPrice(recordDto.getPrice());
        newRecord.setRemark(recordDto.getRemark());
        // User, year, month, addTime, updateTime 会由 bookkeepingService.addRecord() 及其内部逻辑处理

        Bookkeeping savedRecord = bookkeepingService.addRecord(user.getId(), newRecord);
        log.info("管理员成功为用户 {} (ID: {}) 添加了账本记录 ID: {}", userAccount, user.getId(), savedRecord.getId());
        return savedRecord;
    }

    @Override
    @Transactional
    public void adminDeleteUserBookkeepingRecord(String userAccount, Integer recordId) {
        log.info("管理员尝试删除用户 {} 的账本记录 ID: {}", userAccount, recordId);
        User user = userRepository.findByAccount(userAccount)
                .orElseThrow(() -> {
                    log.warn("管理员删除用户账本失败：未找到账号为 {} 的用户。", userAccount);
                    return new EntityNotFoundException("用户未找到，账号: " + userAccount);
                });

        // BookkeepingService.deleteRecord 会校验记录是否存在以及是否属于该用户ID
        bookkeepingService.deleteRecord(recordId, user.getId());
        log.info("管理员成功删除了用户 {} (ID: {}) 的账本记录 ID: {}", userAccount, user.getId(), recordId);
    }

    @Override
    @Transactional
    public Bookkeeping adminUpdateUserBookkeepingRecord(String userAccount, Integer recordId, AdminBookkeepingUpdateRequestDto updateDto) {
        log.info("管理员尝试修改用户 {} 的账本记录 ID: {}", userAccount, recordId);
        User user = userRepository.findByAccount(userAccount)
                .orElseThrow(() -> {
                    log.warn("管理员修改用户账本失败：未找到账号为 {} 的用户。", userAccount);
                    return new EntityNotFoundException("用户未找到，账号: " + userAccount);
                });

        Bookkeeping recordDetailsToUpdate = new Bookkeeping();
        // 将DTO中的值（如果非null）复制到临时的Bookkeeping对象
        recordDetailsToUpdate.setType(updateDto.getType());
        recordDetailsToUpdate.setBookDate(updateDto.getBookDate());
        recordDetailsToUpdate.setCategory(updateDto.getCategory());
        recordDetailsToUpdate.setPrice(updateDto.getPrice());
        recordDetailsToUpdate.setRemark(updateDto.getRemark());
        // BookkeepingService.updateRecord 会校验记录是否存在、是否属于该用户ID，并应用非null的更新

        Bookkeeping updatedRecord = bookkeepingService.updateRecord(recordId, user.getId(), recordDetailsToUpdate);
        log.info("管理员成功修改了用户 {} (ID: {}) 的账本记录 ID: {}", userAccount, user.getId(), updatedRecord.getId());
        return updatedRecord;
    }
}
